package jmine.tec.database.pack.services;

import java.io.Serializable;

import jmine.tec.database.pack.PackException;
import jmine.tec.database.pack.PackingMessages;

import org.hibernate.SessionFactory;

import bancosys.tec.persist.Persistable;
import bancosys.tec.persist.dao.BaseDAO;
import bancosys.tec.persist.dao.BaseDAOFactory;
import bancosys.tec.persist.dao.BeanNotFoundException;

/**
 * Implementação do auxiliar de serviços pack que põe a PK em primeiro lugar de importância.
 * 
 * @author lundberg
 */
public class PkPackEntityServiceHelper implements PackEntityPersistenceHelper {

    private SessionFactory sessionFactory;

    private BaseDAOFactory daoFactory;

    /**
     * {@inheritDoc}
     */
    public <T extends Persistable> T findOrCreate(Class<T> entityClass, Serializable pk, String naturalKey) throws PackException {
        BaseDAO<T> dao = this.daoFactory.getGenericDAO(entityClass);
        try {
            if (pk != null) {
                return this.narrowToSameClass(entityClass, dao, pk, dao.findByPk(pk));
            } else if (naturalKey != null) {
                return this.narrowToSameClass(entityClass, dao, naturalKey, dao.findByNaturalKey(naturalKey));
            } else {
                return dao.createBean();
            }
        } catch (BeanNotFoundException e) {
            return dao.createBean();
        }
    }

    /**
     * Efetua o narrow e verifica se o tipo da entidade lida do banco é exatamente igual.
     * 
     * @param <T> tipo da entidade
     * @param entityClass entityClass
     * @param dao dao
     * @param identifier identifier
     * @param entity entity
     * @return narrowed entity
     * @throws PackException PackException
     */
    private <T extends Persistable> T narrowToSameClass(Class<T> entityClass, BaseDAO<T> dao, Object identifier, T entity)
            throws PackException {
        T narrowed = dao.narrow(entity);
        if (!narrowed.getClass().equals(entityClass)) {
            throw new PackException(PackingMessages.CONFLICTING_ENTITY_TYPE, narrowed.getClass(), entityClass, identifier);
        }
        return narrowed;
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("deprecation")
    public <T extends Persistable> void save(T entity, Serializable pk) {
        if (pk != null && entity.getPk() == null) {
            this.sessionFactory.getCurrentSession().save(entity, pk);
        }
        entity.getPersister().save();
    }

    /**
     * @param daoFactory the daoFactory to set
     */
    public void setDaoFactory(BaseDAOFactory daoFactory) {
        this.daoFactory = daoFactory;
    }

    /**
     * @param sessionFactory the sessionFactory to set
     */
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
}
